package com.coder4j.starter.mybatis;

import com.coder4j.starter.mybatis.annotation.TableAttribute;
import com.coder4j.utils.ObjectUtils;
import com.coder4j.utils.ReflectUtils;
import com.coder4j.utils.StringUtils;
import com.coder4j.starter.web.BaseException;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Provider工具类
 * 提供获取读取表名、字段名等公用方法
 *
 * @author Keller
 * @date 2019-09-12 15:29:19
 */
public class SqlFieldReader {

    /**
     * 数据表名称缓存
     */
    public static ConcurrentHashMap<String, String> tableNameMap = new ConcurrentHashMap<>(16);

    /**
     * 数据表字段缓存
     */
    public static ConcurrentHashMap<String, List<String>> tableFieldMap = new ConcurrentHashMap<>(16);

    /**
     * 读取表名，要求类上有@TableAttribute注解
     *
     * @param entity 实体对象
     * @return tableName
     */
    public static <T> String getTableName(T entity) {
        Class cls = entity.getClass();
        String tableName = tableNameMap.get(cls.getName());
        if (ObjectUtils.noEmpty(tableName)) {
            return tableName;
        }
        TableAttribute table = entity.getClass().getAnnotation(TableAttribute.class);
        if (table == null) {
            throw new BaseException("需要解析表名，但未找到@TableAttribute注解");
        }
        tableNameMap.put(cls.getName(), table.value());
        return table.value();
    }

    /**
     * 生成查询条件，所有有值的字段都会作为查询条件
     *
     */
//    private static <T> String getConditionSuffix(T entity) {
//        StringBuilder builder = new StringBuilder();
//        List<String> fields = getFields(entity);
//        for (String field : fields) {
//            if (ReflectUtils.hasValue(entity, field)) {
//                builder.append(" ")
//                        .append(StringUtils.humpToLine(field))
//                        .append(" =#{entity.")
//                        .append(field)
//                        .append("} ")
//                        .append("AND");
//            }
//        }
//        if (builder.length() > 0) {
//            return " WHERE " + builder.substring(0, builder.lastIndexOf("AND"));
//        }
//        return "";
//    }

    public static <T extends BaseQuery> String getDynamicTableCondition(T query) {
        if(query == null){
            return " ";
        }
        String condition = query.getDefaultCondition();
        if (StringUtils.isEmpty(condition)) {
            return " ";
        }
        condition = condition.trim();

        //检查是否以 where 开头，如果不是，补上 where 关键字
        if (condition.startsWith("WHERE") || condition.startsWith("where")) {
            return " " + condition;
        }

        //如果以<where> 开头，不做特殊处理
        if(condition.startsWith("<where>")){
            return condition;
        }
        return "<where>"+ condition + "</where>";
    }

    public static <T,K extends BaseQuery<T>> String getDefaultOrder(K query){
        return StringUtils.notEmpty(query.getDefaultOrder()) ? " ORDER BY " + query.getDefaultOrder() : "";
    }

    /**
     * 获取所有字段列表
     * 读取类中带@FieldAttribute注解的字段
     *
     * @return {id,name}
     */
    public static <T> List<String> getFields(T entity) {
        Class cls = entity.getClass();
        List<String> fields = tableFieldMap.get(cls.getName());
        if (fields != null && fields.size() > 0) {
            return fields;
        }
        fields = ReflectUtils.getFieldNames(entity);
        tableFieldMap.put(cls.getName(),fields);
        return fields;
    }

    /**
     * 将所有字段名以逗号拼接起来返回
     * 从属性前的@FieldAttribute注解解析要查询的字段名
     * 当所有属性都没有@FieldAttribute注解时，解析所有属性名作为字段名
     *
     * @param entity 实体对象
     * @return id, name
     */
    public static <T> String getFieldStr(T entity) {
        List<String> list = getFields(entity);
        if (list == null || list.isEmpty()) {
            return "";
        }
        return String.join(",", list);
    }

    public static <T> String getFieldStrWithAliasTableName(T entity) {
        List<String> list = getFields(entity);
        if (list == null || list.isEmpty()) {
            return "";
        }

        String string = String.join(",tbl.", list);
        return "tbl."+string;
    }
}
